/* global bootstrap */


import 'default-passive-events'
import md5 from 'md5'
import _template from 'lodash-es/template'
import _merge from 'lodash-es/merge'
import Storage from './Storage'
import Util from './Util'
import CONST from './const'
import qtDef from './options'
import qtStyle from './style';
import tpl from './tpl';


class Quicktab {

    //实例对象
    static instances = [];

    constructor(option) {


        this._validateBootstrapVer();


        let _this = this;
        //构建样式
        this._buildStyle();

        //参数合并
        this._option = _merge({}, qtDef.DEFAULT, option);

        //容器检测
        this._tab_container = document.querySelector(this._option.selector);
        //第一步检测是否是一个有效的dom容器
        if (!(this._tab_container instanceof HTMLElement)) {
            throw new Error(`selector '${this._option.selector}' invalid`);
        }


        //第二步,检测是否是一个已经被实例化的dom容器
        if (this._tab_container.classList.contains(CONST.TAB_NAMESPACE)) {
            throw new Error(`The provided selector '${this._option.selector}' has been initialized`);
        }

        //每个实例的id是不一样的
        this._qt_id = md5(this._option.selector);
        this._qt_cache_key = `${CONST.TAB_NAMESPACE}-` + this._qt_id;
        //缓存初始化
        this.storage = this._initCache();


        //设置容器的宽高
        this._setContainerWH();

        //给容器挂载容器所需的类名
        this._tab_container.classList.add(CONST.TAB_NAMESPACE);

        //加入到容器中
        this._tab_container.insertAdjacentHTML('beforeEnd', _template(tpl.TAB_MAIN_TPL)({'options': this._option}));
        //tab的容器
        this._tab_wraper = this._tab_container.querySelector(`li.flex-grow-1 > .${CONST.TAB_SCROLL_AREA_CLASS_NAME}`);
        //tab面板的容器
        this._tab_pane_wraper = this._tab_container.querySelector('div.flex-grow-1');

        // 选项可通过data属性覆盖
        this._dataAttrAssign();

        //回显tab(可能是缓存里的，或者是option选项里面的)
        this._restoreTabs();


        //注册必须的事件
        this._registerRequiredEvents();

        if (this._option.tabConfig.contextmenu.enable === true) {
            //构建dom
            this._buildContextmenu();

            //事件绑定
            this._registerContextmenuEvent();

        }


        //事件监听开始根据参数来进行绑定
        //左边滑动
        if (this._option.toolbar.leftScroll.enable === true) {
            Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_MOVE_LEFT_BTN_CLASS_NAME}`, function () {
                _this.leftScroll();
            });
        }

        //右边滑动
        if (this._option.toolbar.rightScroll.enable === true) {
            Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_MOVE_RIGHT_BTN_CLASS_NAME}`, function () {
                _this.rightScroll();
            });
        }


        //全屏
        if (this._option.toolbar.fullscreen.enable === true) {
            Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_FULLSCREEN_TRIGGER_CLASS_NAME}`, function () {

                if (this.getElementsByClassName(`${_this._option.toolbar.fullscreen.icon}`).length > 0) {
                    _this.fullscreen();
                } else {
                    _this.exitFullscreen();
                }
            });
        }

        //刷新
        if (this._option.toolbar.refresh.enable === true) {
            Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_REFRESH_TRIGGER_CLASS_NAME}`, function () {
                _this.refreshActiveTab();
            });
        }

        //更多菜单的每个item判断
        if (this._option.toolbar.moreDropdowns.enable === true) {

            //更多操作的下拉菜单
            let tabActionsDropdown = this._tab_container.querySelector('ul>li.dropdown>button');
            tabActionsDropdown.addEventListener('show.bs.dropdown', () => {
                _this._tab_container.classList.add(CONST.TAB_MORE_ACTION_DROPDOWNS_POINTER_EVENTS_CLASS_NAME);
            })
            //更多操作下拉菜单关闭移除
            tabActionsDropdown.addEventListener('hide.bs.dropdown', () => {
                _this._tab_container.classList.remove(CONST.TAB_MORE_ACTION_DROPDOWNS_POINTER_EVENTS_CLASS_NAME);
            })

            //回到当前
            if (this._option.toolbar.moreDropdowns.items.rollback.enable === true) {
                Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_DROPDOWN_ROLLBACK_CURRENT_CLASS_NAME}`, function () {
                    _this.scrollToActiveTab();
                });
            }

            //刷新当前
            if (this._option.toolbar.moreDropdowns.items.reload.enable === true) {
                Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_DROPDOWN_REFRESH_CURRENT_CLASS_NAME}`, function () {
                    _this.refreshActiveTab();
                });
            }

            //关闭当前
            if (this._option.toolbar.moreDropdowns.items.close.enable === true) {
                Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_DROPDOWN_CLOSE_CURRENT_CLASS_NAME}`, function () {
                    _this.closeActiveTab();
                });
            }


            //关闭其它
            Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_DROPDOWN_CLOSE_OTHER_CLASS_NAME}`, function () {
                _this.closeExceptActiveTab();
            });

            //关闭全部
            Util.delegate(_this._tab_container, 'click', `.${CONST.TAB_TOOLBAR_DROPDOWN_CLOSE_ALL_CLASS_NAME}`, function () {
                _this.closeAllTabs();
            });
        }


        //tab关闭
        if (this._option.tabConfig.closeBtn.enable === true) {
            Util.delegate(_this._tab_wraper, 'click', `.${CONST.TAB_CLOSE_BTN_ICON_CLASS_NAME}`, function () {
                _this.closeTabById(Quicktab.getTabId(this.parentNode));
            });
        }


        //鼠标滚轮可以切换tab
        if (this._option.tabConfig.mouseWheelToggleTab === true) {
            let _this = this;
            this._tab_wraper.addEventListener('wheel', Util.debounce(function (e) {
                e.preventDefault();
                let activeTab = _this.getActiveTab();

                //滚动的时候必须关闭tab的右键菜单
                if (_this._option.tabConfig.contextmenu.enable === true) {
                    _this._closeTabsContextmenu();
                }

                let deltaY = e.deltaY;
                if (deltaY < 0) {//向左滚动

                    //获取它前一个tab
                    let preTab = activeTab.previousElementSibling;
                    if (preTab instanceof HTMLElement) {
                        _this.activeTabById(Quicktab.getTabId(preTab))
                    }

                } else if (deltaY > 0) {//向右滚动
                    let nextTab = activeTab.nextElementSibling;
                    if (nextTab instanceof HTMLElement) {
                        _this.activeTabById(Quicktab.getTabId(nextTab))
                    }

                }

            }, 100));
        }

        //是否开启tab的拖动排序
        if (this._option.tabConfig.dragSort === true) {

            //当前拖动的元素
            let dragging = null;

            //拖拽开始
            _this._tab_wraper.ondragstart = function (event) {
                dragging = event.target;

                //拖动的时候关闭右键菜单显示
                if (_this._option.tabConfig.contextmenu.enable === true) {
                    _this._closeTabsContextmenu();
                }
            }

            //拖拽移动中
            _this._tab_wraper.ondragover = function (event) {
                // 默认无法将数据/元素放置到其他元素中。如果需要设置允许放置，必须阻止对元素的默认处理方式
                event.preventDefault();
                let target = event.target;


                //当前拖动的元素是li 且不等于
                if (target.nodeName === 'BUTTON' && target !== dragging) {


                    // 获取初始位置
                    let targetRect = target.getBoundingClientRect()
                    let draggingRect = dragging.getBoundingClientRect()


                    if (target) {
                        // 判断是否动画元素
                        if (target.animated) {
                            return;
                        }
                    }


                    if (_this._index(dragging) < _this._index(target)) {
                        // 目标比元素大，插到其后面
                        // extSibling下一个兄弟元素
                        target.parentNode.insertBefore(dragging, target.nextSibling)
                    } else {
                        // 目标比元素小，插到其前面
                        target.parentNode.insertBefore(dragging, target)
                    }
                    _this._animate(draggingRect, dragging)
                    _this._animate(targetRect, target)
                }
            }
            //拖拽结束
            _this._tab_wraper.ondragend = function (event) {
                dragging = null;
            }

        }


        //静态属性存实例对象,用于子页面快速找到父级页面实例，然后添加tab等..
        Quicktab.instances[this._qt_id] = this;

        //实例化完毕回调
        if (this._option.onInit) {
            this._option.onInit({target: this});
        }

    }


    _registerRequiredEvents() {
        let _this = this;

        //监听窗口变化也要让右键菜单消失
        window.addEventListener('resize', Util.debounce(function () {

            if (_this._option.tabConfig.contextmenu.enable === true) {
                //关闭tab的右键菜单
                _this._closeTabsContextmenu();
            }

            //隐藏更多菜单
            _this._moreMenuDropdownHide();

            //回到当前位置
            if (_this._option.toolbar.moreDropdowns.enable === true && _this._option.toolbar.moreDropdowns.items.rollback.enable === true && _this._option.tabConfig.windowResizeRollback === true) {
                _this.scrollToActiveTab();
            }

        }, 150));


        //快速通过html属性注册tab
        Util.delegate(document.body, 'click', '[data-qt-tab][data-qt-target]', function (e) {
            e.preventDefault();
            if (this.getAttribute('data-qt-target') === _this._option.selector) {
                let tab = _this._mergeTab(JSON.parse(this.getAttribute('data-qt-tab')))
                _this.addTab(tab);
            }
        });


        //tab的单击事件
        Util.delegate(_this._tab_wraper, 'click', 'button.nav-link', function (e) {
            e.preventDefault();


            let tabId = Quicktab.getTabId(this);


            if (_this._option.onTabClick) {
                _this._option.onTabClick(_this._getCallBackParamsById(tabId));
            }

            //激活
            _this.activeTabById(tabId);
            //滚动到tab所在位置
            if (_this._option.tabConfig.clickRollback === true) {
                _this.scrollToTabById(tabId);
            }
        }, `.${CONST.TAB_CLOSE_BTN_ICON_CLASS_NAME}`);

    }


    _initCache() {
        if (this._option.cache === 'localStorage') {
            return new Storage(2);
        } else if (this._option.cache === 'sessionStorage') {
            return new Storage(1);
        } else {
            return null;
        }
    }


    //静态方法
    static getTabId(tabEl) {
        return tabEl.getAttribute(CONST.TAB_ID_KEY)
    }

    static getTabUrl(tabEl) {
        return tabEl.getAttribute(CONST.TAB_URL_KEY)
    }

    static canAccessIFrame(iframe) {
        return Util.canAccessIFrame(iframe);
    }

    static getTabIdByUrl(url) {
        return md5(url);
    }

    // 模仿tinymce插件的方式获取实例tinymce.get('editor').setContent('<h1>这是回显的内容</h1>')
    static get(selector) {
        return Quicktab.instances[md5(selector)];
    }


    _buildStyle() {
        let styleEl = document.querySelector(`style[namespace="${CONST.TAB_NAMESPACE}"]`);
        if (!(styleEl instanceof HTMLStyleElement)) {
            let style = document.createElement('style');
            style.setAttribute('namespace', CONST.TAB_NAMESPACE);
            style.textContent = qtStyle.style;
            document.head.appendChild(style);
        }
    }

    _buildContextmenu() {
        //加入到body
        document.body.insertAdjacentHTML('beforeEnd', _template(tpl.TBA_CONTEXTMENU_TPL)({
            options: this._option,
            id: this._qt_id
        }));
        this._tab_contextmenu_wraper = document.querySelector(`.${CONST.TAB_CONTEXTMENU_CONTAINER_CLASS_NAME}-${this._qt_id}`);
    }

    _registerContextmenuEvent() {
        let _this = this;
        //tab右键
        Util.delegate(_this._tab_wraper, 'contextmenu', 'button.nav-link', function (e) {
            e.preventDefault();

            let id = Quicktab.getTabId(this);

            //同时查看是否需要显示关闭选项
            if (_this._option.tabConfig.contextmenu.items.close.enable === true) {
                if (_this._canRemoveTabById(id)) {
                    _this._tab_contextmenu_wraper.querySelector(`.${CONST.TAB_CONTEXTMENU_CLOSE_CLASS_NAME}`).style.display = 'block';
                } else {
                    _this._tab_contextmenu_wraper.querySelector(`.${CONST.TAB_CONTEXTMENU_CLOSE_CLASS_NAME}`).style.display = 'none';
                }
            }


            _this._tab_contextmenu_wraper.style.top = `${e.clientY}px`;
            _this._tab_contextmenu_wraper.style.left = `${e.clientX}px`;
            _this._tab_contextmenu_wraper.style.display = 'block';

            //同时给iframe窗口禁用所有的鼠标事件
            _this._tab_container.classList.add(CONST.TAB_CONTEXTMENU_POINTER_EVENTS_CLASS_NAME);


            //如果此时下拉菜单是打开着的，需要给它关闭掉
            _this._moreMenuDropdownHide();


            //把所有的id都给遍历给右键菜单的每一项
            _this._tab_contextmenu_wraper.querySelectorAll('button.list-group-item').forEach(function (item) {
                item.setAttribute(CONST.TAB_ID_KEY, id);
            })

        });

        //点击任何区域左键单击都关闭
        document.addEventListener('click', function () {
            _this._closeTabsContextmenu();
        })

        //内容区域的右键也要能关闭这个tab右键菜单
        Util.delegate(_this._tab_container, 'contextmenu', 'div.flex-grow-1', function (e) {
            e.preventDefault();
            _this._closeTabsContextmenu();
            _this._moreMenuDropdownHide();
        });


        //tab右键刷新左击处理
        Util.delegate(_this._tab_contextmenu_wraper, 'click', `.${CONST.TAB_CONTEXTMENU_REFRESH_CLASS_NAME}`, function (e) {
            e.preventDefault();
            _this.refreshTabById(this.getAttribute(CONST.TAB_ID_KEY));
            _this._closeTabsContextmenu()

        });


        //tab右键刷新右击处理
        Util.delegate(_this._tab_contextmenu_wraper, 'contextmenu', `.${CONST.TAB_CONTEXTMENU_REFRESH_CLASS_NAME}`, function (e) {
            e.preventDefault();
            _this.refreshTabById(this.getAttribute(CONST.TAB_ID_KEY));
            _this._closeTabsContextmenu()

        });


        //右键菜单-关闭左击处理
        Util.delegate(_this._tab_contextmenu_wraper, 'click', `.${CONST.TAB_CONTEXTMENU_CLOSE_CLASS_NAME}`, function (e) {
            e.preventDefault();

            _this.closeTabById(this.getAttribute(CONST.TAB_ID_KEY));
            _this._closeTabsContextmenu();

        });

        //右键菜单-关闭右击处理
        Util.delegate(_this._tab_contextmenu_wraper, 'contextmenu', `.${CONST.TAB_CONTEXTMENU_CLOSE_CLASS_NAME}`, function (e) {
            e.preventDefault();
            _this.closeTabById(this.getAttribute(CONST.TAB_ID_KEY));
            _this._closeTabsContextmenu();
        });


        //右键菜单-关闭其它左击处理
        Util.delegate(_this._tab_contextmenu_wraper, 'click', `.${CONST.TAB_CONTEXTMENU_CLOSE_OTHER_CLASS_NAME}`, function (e) {
            e.preventDefault();

            _this.closeTabsExceptById(Quicktab.getTabId(this));
            _this._closeTabsContextmenu()
        });

        //右键菜单-关闭其它右击处理
        Util.delegate(_this._tab_contextmenu_wraper, 'contextmenu', `.${CONST.TAB_CONTEXTMENU_CLOSE_OTHER_CLASS_NAME}`, function (e) {
            e.preventDefault();
            _this.closeTabsExceptById(Quicktab.getTabId(this));
            _this._closeTabsContextmenu()
        });
    }


    addTab(option) {

        //参数合并
        option = this._mergeTab(option);

        if (this.getTabById(option.id) === null) { //如果没有该tab则添加这个tab


            if (this._option.tabConfig.maxNum >= 1) {

                let canCloseTabs = [];
                let tabs = this._tab_wraper.children;
                for (let tab of tabs) {
                    if (this._canRemoveTabById(Quicktab.getTabId(tab))) {
                        canCloseTabs.push(tab);
                    }
                }
                //如果=1那就把全部都给删了
                if (this._option.tabConfig.maxNum === 1) {
                    for (let tab of canCloseTabs) {
                        this._removeTabById(Quicktab.getTabId(tab));
                    }
                } else {
                    //判断是否已经达到了最大的tab数量,把第一个给移除
                    if (canCloseTabs.length >= this._option.tabConfig.maxNum) {

                        //得到需要排除的tab
                        let tabs = canCloseTabs.slice(0, -(this._option.tabConfig.maxNum - 1));
                        for (let tab of tabs) {
                            this._removeTabById(Quicktab.getTabId(tab));
                        }
                    }
                }

            }


            //添加tab
            this._tab_wraper.insertAdjacentHTML('beforeEnd', _template(tpl.TAB_TPL)({
                'options': this._option,
                'option': option
            }));

            //添加面板容器
            this._tab_pane_wraper.insertAdjacentHTML('beforeEnd', _template(tpl.TAB_PANE_TPL)({
                'options': this._option,
                'option': option
            }));

            //同时也添加进缓存
            this._addTabToCache(option);

        }

        //激活该tab
        this.activeTabById(option.id);
        //滚动到tab所在位置
        this.scrollToTabById(option.id);
    }


    activeTabById(id) {

        let _this = this;


        //先判断该tab是否已经被激活
        if (_this.getTabById(id).classList.contains(CONST.TAB_ACTIVE_CLASS_NAME)) {
            return;
        }

        //激活缓存中的tab
        _this._activeCacheTabById(id);


        //删除前一个tab的激活样式
        let preActiveTab = _this.getActiveTab();
        if (preActiveTab instanceof HTMLElement) {
            preActiveTab.classList.remove(CONST.TAB_ACTIVE_CLASS_NAME)
        }


        //给当前tab添加激活样式
        this.getTabById(id).classList.add('active');


        //给面板激活(先给所有的面板都加上.outing类，然后再把当前的面板移除该类)
        for (let tab_pane of _this._tab_pane_wraper.children) {
            tab_pane.classList.add(CONST.TAB_PANE_HIDE_CLASS_NAME);
        }


        //先查找该面板是否存在(因为可能是惰性tab)
        let tabPane = _this.getTabPaneById(id);
        if (!(tabPane instanceof HTMLElement)) {
            _this._addTabPaneById(id);
        }

        //找到面板下的iframe添加事件
        _this._addIframeEventById(id);

        //给当前的面板移进视野
        _this.getTabPaneById(id).classList.remove(CONST.TAB_PANE_HIDE_CLASS_NAME);

        //滚动到指定的tab区域
        // _this.scrollToTabById(id);

        //tab激活事件回调,给用户处理事件
        if (_this._option.onTabActivated) {
            _this._option.onTabActivated(_this._getCallBackParamsById(id));
        }
    }


    scrollToTabById(id, smooth = true) {

        let tab = this.getTabById(id);

        this._tab_wraper.scrollTo({
            //需要父元素设置postion(relative、absolute、fixed)
            // 获取到当前点击元素的 offsetLeft  - 包裹盒子 offsetWidth 的一半 + 当前点击元素 offsetWidth 的一半
            left: tab.offsetLeft - this._tab_wraper.offsetWidth / 2 + tab.offsetWidth / 2,
            behavior: smooth === true ? 'smooth' : 'auto'
        })
    }


    getTabById(id) {
        return this._tab_wraper.querySelector(`[data-tab-id="${id}"]`);
    }


    _getTabMaskById(id) {
        let tabPane = this.getTabPaneById(id);
        if (tabPane instanceof HTMLElement) {
            return tabPane.querySelector('div');
        }
        return null;
    }

    clsoeTabMaskById(id) {
        let loading = this._getTabMaskById(id);
        if (loading instanceof HTMLElement) {//如果已经存在就删除
            loading.remove();
        }
    }

    addTabMaskById(id) {
        //关闭遮罩层
        this.clsoeTabMaskById(id);
        //判断该tab面板是否存在
        let tabPane = this.getTabPaneById(id);
        if (tabPane instanceof HTMLElement) {
            tabPane.insertAdjacentHTML('beforeEnd', tpl.TAB_LOADING_TPL);
        }
    }


    getActiveTab() {
        return this._tab_wraper.querySelector('button.nav-link.active');
    }


    getIFrameById(id) {
        let tabPane = this.getTabPaneById(id);
        let iframe = null;
        if (tabPane instanceof HTMLElement) {
            iframe = tabPane.querySelector('iframe');
        }
        return iframe;
    }


    getTabPaneById(id) {
        return this._tab_pane_wraper.querySelector(`[data-tab-id="${id}"]`);
    }


    _restoreTabs() {

        //判断选项是否开启缓存
        if (this._isCache()) {
            let cacheTabs = this._getCacheTabs();
            if (cacheTabs.length !== 0) {
                this._restoreTabsHandle(cacheTabs, this._getActiveTabFromCache().id);
            } else {
                //要缓存
                this._restoreTabsHandle(this._option.tabs, null, true);
            }

        } else {
            //删除缓存
            Storage.removeBoth(this._qt_cache_key);
            //回显处理程序
            this._restoreTabsHandle(this._option.tabs);


        }
    }


    closeTabById(id) {

        let tab = this.getTabById(id);

        if (tab instanceof HTMLElement && this._canRemoveTabById(id)) {//如果tab真实存在,且tab可以删除
            if (tab.classList.contains('active')) {//判断是否是激活的tab
                //把active传递给其它的tab
                let willActiveId = null;
                if (tab.nextElementSibling instanceof HTMLElement) {//后面有tab
                    //得到后面tab的pageid作为将要激活的tab id


                    willActiveId = Quicktab.getTabId(tab.nextElementSibling);
                } else if (tab.previousElementSibling instanceof HTMLElement) { //看看前面是否有tab

                    willActiveId = Quicktab.getTabId(tab.previousElementSibling);
                }

                //先删除再滚动
                this._removeTabById(id)
                if (willActiveId) {//如果该id存在就激活
                    //激活
                    this.activeTabById(willActiveId);
                }

            } else { //不是激活的tab直接删除

                this._removeTabById(id)
            }
        }


    }


    _removeTabById(id) {

        //删除tab
        this.getTabById(id).remove();

        //删除tab面板
        let tabPane = this.getTabPaneById(id);
        if (tabPane instanceof HTMLElement) {
            tabPane.remove();
        }

        // 删除缓存里面的tab
        this._removeCacheTabById(id);

    }


    /**
     * 添加tab进缓存
     * @param option
     * @private
     */
    _addTabToCache(option) {
        if (this._isCache()) {
            //先取
            let tabs = this._getCacheTabs();
            //追加属性 active
            option.active = false;
            tabs.push(option)
            //重新设置回去
            this.storage.set(this._qt_cache_key, tabs);
        }
    }

    _getCacheTabs() {
        if (this._isCache()) {
            let tabs = this.storage.get(this._qt_cache_key);
            return tabs === null ? [] : tabs;
        }
    }


    _isCache() {
        return this._option.cache !== false;
    }


    _mergeTab(tabOption) {
        let option = _merge({}, qtDef.TABDEFAULT, tabOption);
        option.id = md5(option.url);
        return option;
    }

    /**
     *
     * @param tabs tab数组
     * @param activeId   待激活的id,不填默认激活tabs的最后一项
     * @param cache   是否添加进缓存 默认：false  true：同时添加进本地缓存
     * @private
     */
    _restoreTabsHandle(tabs, activeId = null, cache = false) {
        let _this = this;


        if (!(Array.isArray(tabs) && tabs.length !== 0)) {
            return;
        }


        let newTabArr = [];
        tabs.forEach((option) => {
            newTabArr.push(_this._mergeTab(option))
        });

        //bug:fix,如果添加两个url相同的tab以然会添加上去，导致点击无效，这里应该进行去重
        let uniTabArr = Util.arrUnique(newTabArr, 'id');


        //创建两个虚拟节点
        let tabFrag = document.createDocumentFragment();
        //这里只添加所有的tab，不添加iframe,否则全部加载iframe将会卡爆(重点优化)
        for (let option of uniTabArr) {
            if (cache === true) {
                _this._addTabToCache(option);
            }


            let tabHTML = _template(tpl.TAB_TPL)({
                'options': this._option,
                'option': option
            });

            tabFrag.appendChild(Util.createNode(tabHTML));
        }

        //添加虚拟节点到tab的容器里面
        _this._tab_wraper.appendChild(tabFrag);
        if (activeId !== null) {
            //激活该tab
            _this.activeTabById(activeId);
            //并滚动到tab所在位置
            _this.scrollToTabById(activeId, false);
        } else {
            //激活数组里最后一个tab
            let id = newTabArr.at(-1).id;
            _this.activeTabById(id);
            //并滚动到tab所在位置
            _this.scrollToTabById(id, false);
        }

    }


    _getActiveTabFromCache() {
        if (this._isCache()) {
            let tab = null;
            this._getCacheTabs().forEach((option) => {
                if (Object.prototype.hasOwnProperty.call(option, 'active') && option.active === true) {
                    tab = option;
                }
            })
            return tab;
        }
    }


    _activeCacheTabById(id) {

        if (this._isCache()) {
            let cacheTabs = this._getCacheTabs();
            cacheTabs.forEach((option) => {
                option.active = option.id === id;
            });
            this.storage.set(this._qt_cache_key, cacheTabs)
        }
    }


    _addTabPaneById(id, active = true) {
        let tab = this.getTabById(id);

        let tabPaneStr = _template(tpl.TAB_PANE_TPL)({
            'options': this._option,
            'option': {
                id: Quicktab.getTabId(tab),
                url: Quicktab.getTabUrl(tab)
            }
        });

        let tabPaneNode = Util.createNode(tabPaneStr);

        //如果不是激活的直接给它添加上hide类
        if (active === false) {
            tabPaneNode.classList.add(CONST.TAB_PANE_HIDE_CLASS_NAME);
        }

        this._tab_pane_wraper.appendChild(tabPaneNode);

    }


    _removeCacheTabById(id) {
        if (this._isCache()) {
            let cacheTabs = this._getCacheTabs();
            cacheTabs.forEach((tab, index) => {
                if (tab.id === id) {
                    cacheTabs.splice(index, 1)
                }
            })
            //重新设置回去
            this.storage.set(this._qt_cache_key, cacheTabs)
        }
    }


    refreshTabById(id) {

        let tabPane = this.getTabPaneById(id);
        if (!(tabPane instanceof HTMLElement)) {//没有的话需要添加tab面板还有注册iframe的事件
            this._addTabPaneById(id, false);
            this._addIframeEventById(id);
        } else {//如果有就正常刷新逻辑

            this.addTabMaskById(id);

            //在这里还需要判断是否存在跨域的情况，否则刷新功能会报错
            let iframe = this.getIFrameById(id);
            if (Quicktab.canAccessIFrame(iframe)) {
                iframe.contentWindow.location.reload();
            } else {
                iframe.setAttribute('src', iframe.getAttribute('src'));// 跨域状况下，重新设置url
            }
        }
    }


    _canRemoveTabById(id) {
        return (this.getTabById(id).querySelector(`.${CONST.TAB_CLOSE_BTN_ICON_CLASS_NAME}`) instanceof HTMLElement);
    }


    _closeTabsContextmenu() {
        this._tab_contextmenu_wraper.style.display = 'none';
        this._tab_container.classList.remove(CONST.TAB_CONTEXTMENU_POINTER_EVENTS_CLASS_NAME);
    }


    _moreMenuDropdownHide() {
        if (this._option.toolbar.moreDropdowns.enable === true) {
            bootstrap.Dropdown.getOrCreateInstance(this._tab_container.querySelector('ul>li.dropdown>button')).hide();
        }
    }


    scrollToActiveTab() {
        let activeTab = this.getActiveTab();
        if (activeTab instanceof HTMLElement) {
            this.scrollToTabById(Quicktab.getTabId(activeTab));
        }
    }


    refreshActiveTab() {
        let activeTab = this.getActiveTab();
        if (activeTab instanceof HTMLElement) {
            this.refreshTabById(Quicktab.getTabId(activeTab));
        }
    }


    setTab(callBack) {

        let params = [];

        let tabs = this._tab_wraper.children;
        for (let tab of tabs) {
            let p = this._getCallBackParamsById(Quicktab.getTabId(tab));
            params.push(p);
        }

        callBack(params);
    }


    fullscreen() {

        if (this._option.toolbar.fullscreen.enable === true) {
            //不管如何它都要替换成退出全屏的图标
            this._tab_container.querySelector(`.${CONST.TAB_FULLSCREEN_TRIGGER_CLASS_NAME}`).innerHTML = `<i class="${this._option.toolbar.fullscreen.exitIcon}"></i>`

            document.documentElement.style.overflow = 'hidden';
            this._tab_container.classList.add(CONST.TAB_FULLSCREEN_CLASS_NAME);

            //回调
            if (this._option.toolbar.fullscreen.fullscreen) {
                this._option.toolbar.fullscreen.fullscreen(this);
            }

        }

    }


    exitFullscreen() {
        if (this._option.toolbar.fullscreen.enable === true) {

            this._tab_container.querySelector(`.${CONST.TAB_FULLSCREEN_TRIGGER_CLASS_NAME}`).innerHTML = `<i class="${this._option.toolbar.fullscreen.icon}"></i>`
            document.documentElement.style.overflow = 'auto';
            this._tab_container.classList.remove(CONST.TAB_FULLSCREEN_CLASS_NAME);

            //退出全屏回调
            if (this._option.toolbar.fullscreen.exitFullscreen) {
                this._option.toolbar.fullscreen.exitFullscreen(this);
            }

            //回到当前
            this.scrollToActiveTab();
        }
    }

    leftScroll() {
        this._tab_wraper.scrollTo({
            left: this._tab_wraper.scrollLeft - this._tab_wraper.offsetWidth,
            behavior: 'smooth'
        })
    }

    rightScroll() {
        this._tab_wraper.scrollTo({
            left: this._tab_wraper.scrollLeft + this._tab_wraper.offsetWidth,
            behavior: 'smooth'
        })
    }

    _dataAttrAssign() {
        let tabs = JSON.parse(this._tab_container.getAttribute('data-qt-tabs'));
        if ((Array.isArray(tabs) && tabs.length > 0)) {//有传递，且能解析出正确的格式就更改选项数据
            Util.updateObjDataByKey(this._option, 'tabs', tabs);
        }
    }


    _addIframeEventById(id) {
        let _this = this;
        let iframe = _this.getIFrameById(id);
        iframe.onload = function () {

            if (Quicktab.canAccessIFrame(iframe)) {//如果不是跨域的iframe才给刷新
                iframe.contentWindow.onunload = function () {
                    _this.addTabMaskById(id);
                }
            }

            //触发
            if (_this._option.onTabLoaded) {
                _this._option.onTabLoaded(_this._getCallBackParamsById(id));
            }

            let loading = _this._getTabMaskById(id);

            if (loading instanceof HTMLElement) {
                //fade out
                loading.classList.replace('show', 'hide');
                //监听loadding层执行完毕后给它移除掉。
                loading.addEventListener('transitionend', function () {
                    this.remove();
                    //加载层淡出过渡执行完毕
                    if (_this._option.onTabMaskTransitionend) {
                        _this._option.onTabMaskTransitionend(_this._getCallBackParamsById(id));
                    }
                });
            }
        };
    }


    _getCallBackParamsById(id) {
        let _this = this;
        let tabEl = _this.getTabById(id);
        let tabId = Quicktab.getTabId(tabEl);
        let tabUrl = Quicktab.getTabUrl(tabEl);
        let tabPaneEl = _this.getTabPaneById(id);
        let tabIFrame = {
            el: _this.getIFrameById(id),
            canAccess: Quicktab.canAccessIFrame(_this.getIFrameById(id))
        }
        return {target: _this, tabEl, tabId, tabUrl, tabPaneEl, tabIFrame};
    }

    _setContainerWH() {

        if (Util.isString(this._option.height) && this._option.height.trim().length !== 0) {
            this._tab_container.style.setProperty('height', this._option.height, 'important');
        }
        if (Util.isString(this._option.width) && this._option.width.trim().length !== 0) {
            this._tab_container.style.setProperty('width', this._option.width, 'important');
        }
        if (Util.isString(this._option.minHeight) && this._option.minHeight.trim().length !== 0) {
            this._tab_container.style.setProperty('min-height', this._option.minHeight, 'important');
        }
    }


    closeActiveTab() {
        let activeTab = this.getActiveTab();
        if (activeTab instanceof HTMLElement) {
            let id = Quicktab.getTabId(activeTab);
            if (this._canRemoveTabById(id)) {//判断能不能删除
                this.closeTabById(id)
            }
        }

    }


    closeTabsExceptById(id) {
        let _this = this;
        this._tab_wraper.querySelectorAll('button.nav-link').forEach((tab) => {
            let forEachId = Quicktab.getTabId(tab);
            if (forEachId !== id && _this._canRemoveTabById(forEachId)) {//如果不相等，且tab可以被删除的情况下
                _this.closeTabById(forEachId);
            }
        });
    }


    closeExceptActiveTab() {
        let activeTab = this.getActiveTab();
        if (activeTab instanceof HTMLElement) {
            this.closeTabsExceptById(Quicktab.getTabId(activeTab));
        }
    }


    closeAllTabs() {
        let _this = this;

        this._tab_wraper.querySelectorAll('button.nav-link').forEach((tab) => {
            let id = Quicktab.getTabId(tab);
            if (_this._canRemoveTabById(id)) {
                _this._removeTabById(id);
            }
        });

        //选中那些禁止删除的取第一个,将其激活
        let lastTab = this._tab_wraper.lastChild;
        if (lastTab instanceof HTMLElement) {
            _this.activeTabById(Quicktab.getTabId(lastTab));
        }
    }

    _getBootstrap5Version() {
        let versionArr = [];
        try {
            let bsv = bootstrap.Modal.VERSION;
            if (bsv.indexOf('-') !== -1) {//有可能是后面包含有-beta1或者5.0.0-alpha1
                bsv = bsv.substring(0, bsv.indexOf('-'));
            }
            versionArr.push(...[parseInt(bsv.split('.')[0]), parseInt(bsv.split('.')[1]), parseInt(bsv.split('.')[2])])
        } catch (err) {
            //do something
        }
        return versionArr;
    }

    _validateBootstrapVer() {
        if (typeof bootstrap === 'undefined') {
            throw new Error(`${CONST.TAB_NAMESPACE} must requires bootstrap`);
        }

        let v = this._getBootstrap5Version();
        if (v.length !== 0 && (!(v[0] >= 5 && v[0] === 5 && v[1] >= 1) || (v[0] === 5 && v[1] === 1 && v[2] < 3))) {
            throw new Error(`${CONST.TAB_NAMESPACE} JavaScript requires Bootstrap version 5.1.3 or higher`)
        }

    }


    // 获取元素在父元素中的index
    _index(el) {
        let index = 0
        if (!el || !el.parentNode) {
            return -1
        }
        // previousElementSibling：上一个兄弟元素
        while (el && (el = el.previousElementSibling)) {
            index++
        }
        return index
    }

    // 触发动画
    _animate(prevRect, target) {
        let ms = 300
        if (ms) {
            let currentRect = target.getBoundingClientRect();
            if (prevRect.nodeType === 1) {
                prevRect = prevRect.getBoundingClientRect();
            }

            target.style.setProperty('transition', 'none');
            target.style.setProperty('transform', `translate3d(${prevRect.left - currentRect.left}px,${prevRect.top - currentRect.top}px,0)`);

            target.offsetWidth; // 触发重绘


            target.style.setProperty('transition', `transform ${ms}ms`);
            target.style.setProperty('transform', 'translate3d(0,0,0)');

            // 时间到了之后把transition和transform清空
            clearTimeout(target.animated);
            target.animated = setTimeout(function () {
                target.style.setProperty('transition', '');
                target.style.setProperty('transform', '');
                target.animated = false;
            }, ms);
        }
    }


}

export default Quicktab